package indi.lqzhi.tcpserver.base;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.ResourceLeakDetector;
import lombok.extern.slf4j.Slf4j;

import java.net.SocketAddress;

/**
 * @Author: LQZhi
 * @ClassName: AbstractServer
 * @Date: 2021-09-26 15-27
 * @Description: 服务器的抽象类
 * @Version: V1.0
 */
@Slf4j
public abstract class AbstractServer implements Server {

    /**
     * Netty 服务器引导者
     */
    protected ServerBootstrap serverBootstrap;

    /**
     * 连接线程池，负责接受新进来的连接，然后将连接注册到工作线程池中去
     */
    protected EventLoopGroup bossGroup;

    /**
     * 工作线程池，负责channel业务数据的读、写
     */
    protected EventLoopGroup workerGrop;

    /**
     * 允许状态标志位
     */
    private volatile boolean hasRuning;

    /**
     * 供给服务器引导者绑定的服务器地址
     * @return socketAddress 服务器绑定的主机和端口地址
     */
    protected abstract SocketAddress configServerAddress();

    /**
     * 供给客户端连接后进行处理的管道
     * @return ChannelHandler 管道处理器，处理读，写事件
     */
    protected abstract ChannelHandler[] configChannelHandler();

    /**
     * 初始化通道对象设置(个人理解为设置处理器)，默认为使用addLast添加configChannelHandler()返回的对象，为空则不设置。
     * @param socketChannel 需要初始化的socket通道
     */
    protected void initChildChannel(SocketChannel socketChannel){
        ChannelHandler[] channelHandlers = configChannelHandler();
        if (channelHandlers != null && channelHandlers.length != 0){
            socketChannel.pipeline().addFirst(channelHandlers);
        }
    }

    @Override
    public void start() {
        if (hasRuning){
            throw new UnsupportedOperationException("The server is down, please re-create the server!");
        }
        //serverBootstrap = SpringUtils.getBean(ServerBootstrap.class);
        serverBootstrap = new ServerBootstrap();
        serverBootstrap.group( new NioEventLoopGroup(),  new NioEventLoopGroup());
        serverBootstrap.channel(NioServerSocketChannel.class);

        bossGroup = serverBootstrap.config().group(); //获取到连接线程池
        workerGrop = serverBootstrap.config().childGroup(); //获取到工作线程池
        serverBootstrap.localAddress(configServerAddress());//配置地址
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                initChildChannel(ch);
            }
        });//配置
        ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
        ChannelFuture channelFuture = serverBootstrap.bind();//异步绑定启动
        //对通道关闭进行监听
        channelFuture.channel().closeFuture().addListener((ChannelFutureListener) future -> stop());
        hasRuning = true;//代表运行状态
    }

    @Override
    public void stop() {
        workerGrop.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

    public boolean hasRuning() {
        return hasRuning;
    }
}
